package com.hddz.comlib.util;

import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MathEval {

	public static char PLUS = '+';
	public static char MINUS = '-';
	public static char MULTI = '*';
	public static char DEVIDE = '/';

	public static char BRACKET_LEFT = '(';
	public static char BRACKET_RIGHT = ')';

	public static double eval(String line) {
		while (line.indexOf(BRACKET_LEFT) != -1) {
			Pattern pattern = Pattern.compile("\\(([^\\(\\)]*?)\\)");
			Matcher matcher = pattern.matcher(line);
			while (matcher.find()) {
				double result = simpleEval(matcher.group(1));
				line = line.replace(matcher.group(), result + "");
			}
		}
		return simpleEval(line);
	}

	@SuppressWarnings("unchecked")
	public static double simpleEval(String line) {
		Stack<Double> valueStack = new Stack<Double>();
		Stack<Character> markStack = new Stack<Character>();

		char ch[] = line.toCharArray();

		String tmpValue = "";
		boolean isOper = false;
		for (int i = 0; i < ch.length; i++) {
			if (ch[i] == PLUS || ch[i] == MINUS || ch[i] == MULTI
					|| ch[i] == DEVIDE) {
				double dv = Double.valueOf(tmpValue).doubleValue();
				if (isOper) {
					double dv1 = valueStack.pop();
					char op = markStack.pop();
					double result = simpleTwoEval(op, dv1, dv);
					dv = result;
				}
				valueStack.push(dv);
				markStack.push(ch[i]);
				tmpValue = "";
				isOper = false;
				if (ch[i] == MULTI || ch[i] == DEVIDE)
					isOper = true;
			} else {
				tmpValue += ch[i] + "";

				if (i == ch.length - 1) {
					double dv = Double.valueOf(tmpValue).doubleValue();
					if (isOper) {
						double dv1 = valueStack.pop();
						char op = markStack.pop();
						double result = simpleTwoEval(op, dv1, dv);
						dv = result;
					}
					valueStack.push(dv);
				}
			}
		}
		valueStack = (Stack<Double>) reverseStack(valueStack);
		markStack = (Stack<Character>) reverseStack(markStack);
		while (valueStack.size() > 1) {
			double v1 = valueStack.pop();
			double v2 = valueStack.pop();
			char op = markStack.pop();
			double result = simpleTwoEval(op, v1, v2);
			valueStack.push(result);
		}
		return valueStack.get(0);
	}

	@SuppressWarnings("unchecked")
	private static Stack<?> reverseStack(Stack<?> stack) {
		Stack reverse = new Stack();
		int stackSize = stack.size();
		for (int i = 0; i < stackSize; i++) {
			reverse.push(stack.pop());
		}
		return reverse;
	}

	private static double simpleTwoEval(char op, double value1, double value2) {
		if (op == PLUS) {
			return value1 + value2;
		} else if (op == MINUS) {
			return value1 - value2;
		} else if (op == MULTI) {
			return value1 * value2;
		} else if (op == DEVIDE) {
			return value1 / value2;
		}
		return 0;
	}
}
